package empe;

import java.util.Random;

/**
 * Classe que cria altera individuos
 */
public class Individuo {
	
	private float conforto;
	private int[][] matriz;
	protected Individuo proximo;
	protected Individuo anterior;
	protected Cap_elemento eventos;
	
	
	
	/**
	 * Construtor para um novo individuo com uma nova matriz pre-calculada
	 * @param matriz matriz pre-calculada para o novo individuo
	 */
	public Individuo (int[][] matriz)
	{
		this.matriz=matriz;
		proximo=null;
		anterior=null;
		eventos=null;
		this.conforto=0;
		calcular_conforto();
	}
	
	/**
	 * Muta o individuo e retorna se ele melhorou ou nao
	 * @return informacao se o individuo mutado melhorou durante a mutacao
	 */
	protected boolean mutar ()
	{
		boolean melhorou;
				
		int[][] referencia=Controlo.ler_C();
		
		Random random = new Random();
		
		int tarefa=random.nextInt(Controlo.ler_m());
		int proc=0;
		
		for(int i=0; i<Controlo.ler_n(); i++)
		{
			if(matriz[i][tarefa]!=0)
			{
				proc=i;
				matriz[i][tarefa]=0;
				break;
			}
		}
		
		int nproc=random.nextInt(Controlo.ler_n()-1);
		
		if (nproc>=proc) proc++;
		
		matriz[nproc][tarefa]=referencia[nproc][tarefa];
		
		melhorou=calcular_conforto();

		return melhorou;
	}
	
	
	/**
	 * Calcula o novo conforto do individuo
	 * @return Informacao se o novo conforto e melhor que o anterior
	 */
	private boolean calcular_conforto()
	{
		float tmin=Controlo.ler_tmin();
		float tz;
		boolean melhorou;
		
		tz = calc_temp_exec();
		
		float antigo=conforto;
		conforto=tmin/tz;
		
		if(conforto>antigo)
			melhorou=true;
		else melhorou=false;
		
		return melhorou;
	}
	
	
	
	/**
	 * Calcula e devolve o tempo de execucao em paralelo
	 * @return tempo de execucao em paralelo
	 */	
	protected float calc_temp_exec() {
		
		float tz=0, sum=0;
		
		
		for(int i=0; i<Controlo.ler_n(); i++)
		{
			sum=0;

			for(int f=0; f<Controlo.ler_m(); f++)
			{
				sum+=matriz[i][f];
			}

			if(sum>tz) 
			{
				tz=sum;
			}
		}
		return tz;
	}
	
	
	
	/**
	 * Retorna o conforto do individuo
	 * @return conforto do individuo
	 */
	protected float ler_conforto()
	{
		return conforto;
	}
	
	/**
	 * Retorna a matriz do individuo
	 * @return matriz do individuo
	 */
	protected int[][] ler_matriz()
	{
		return this.matriz;
	}
	
	/**
	 * Cria um clone do individuo com os apontadores de proximo e anterior a nulo
	 * @return um individuo clone
	 */
	protected Individuo clonar()
	{
		
		int[][] matrix= new int[Controlo.ler_n()][Controlo.ler_m()];
		int i,j;
		
		/*Copia a matriZ para matriX*/
		for(i=0; i < Controlo.ler_n(); i++) {
			for(j=0; j < Controlo.ler_m(); j++) {
				matrix[i][j] = this.matriz[i][j];
			}
		}
		
		
		Individuo novo= new Individuo(matrix);		
		
		return novo;
	}
}
